using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Windows.Media.Imaging;
using System.IO;
using System.Windows.Media;
using System.Threading;

namespace Ricciolo.PaperBoy.Feeds
{
    /// <summary>
    /// Grab favicon.ico beginning from passed uri.
    /// </summary>
    public class FavIconGrabber
    {

        public IAsyncResult BeginGetFavIcon(Uri uri, AsyncCallback callback, Object state)
        {
            FavIconGrabberAsyncResult result = new FavIconGrabberAsyncResult(callback, state);

            TryDirectory(uri, result, 0);

            return result;
        }

        public Stream EndGetFavIcon(IAsyncResult ar)
        {
            if (!(ar is FavIconGrabberAsyncResult))
                throw new ArgumentException("ar");

            return ((FavIconGrabberAsyncResult)ar).Image;
        }

        internal class RequestState
        {
            internal readonly FavIconGrabberAsyncResult Result;
            internal readonly HttpWebRequest Request;

            public RequestState(FavIconGrabberAsyncResult result, HttpWebRequest request)
            {
                this.Result = result;
                this.Request = request;
            }
        }

        private void TryDirectory(Uri uri, FavIconGrabberAsyncResult result, int skip)
        {
            UriBuilder u = new UriBuilder(uri);
            u.Query = String.Empty;
            string uris = u.ToString();
            string directory = uris;

            // Compute uri
            for (int x = 0; x <= skip; x++)
            {
                int slash = directory.LastIndexOf('/');
                // http://
                if (slash < 8)
                {
                    result.Complete(null);
                    return;
                }

                directory = directory.Substring(0, slash);
            }

            // Prepare uri for favicon
            string favIcon = directory + "/favicon.ico";

            // Start webrequest
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(favIcon);
            request.UserAgent = "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0;)";
            request.BeginGetResponse(new AsyncCallback(OnGetResponse), new RequestState(result, request));
        }

        private void OnGetResponse(IAsyncResult ar)
        {
            RequestState state = (RequestState)ar.AsyncState;
            try
            {
                HttpWebResponse response = (HttpWebResponse)state.Request.EndGetResponse(ar);

                if (response.StatusCode == HttpStatusCode.OK && response.ContentType.IndexOf("text/html") < 0)
                {
                    // Complete callback
                    state.Result.Complete(response.GetResponseStream());
                    return;
                }
            }
            catch (WebException we)
            {
            }
            // Try with a root folder
            TryDirectory(state.Request.RequestUri, state.Result, 1);
        }
    }

    public class FavIconGrabberAsyncResult : IAsyncResult
    {

        private ManualResetEvent _event;
        private bool _completed;
        private Stream _image;
        private AsyncCallback callback;
        private Object state;

        public FavIconGrabberAsyncResult(AsyncCallback callback, Object state)
        {
            this.callback = callback;
            this.state = state;
            this._event = new ManualResetEvent(false);
        }

        #region IAsyncResult Members

        object IAsyncResult.AsyncState
        {
            get { return this.state; }
        }

        System.Threading.WaitHandle IAsyncResult.AsyncWaitHandle
        {
            get { return _event; }
        }

        bool IAsyncResult.CompletedSynchronously
        {
            get { return false; }
        }

        bool IAsyncResult.IsCompleted
        {
            get { return _completed; }
        }

        #endregion

        internal Stream Image
        {
            get { return _image; }
        }

        internal void Complete(Stream image)
        {
            _image = image;
            _completed = true;
            _event.Set();

            // Call the callback in other thread
            if (callback != null)
                ThreadPool.QueueUserWorkItem(new WaitCallback(ExecuteCallBack), this);
        }

        private void ExecuteCallBack(object asyncResult)
        {
            ((FavIconGrabberAsyncResult)asyncResult).callback(this);
        }
    }
}
